package com.epfly.sdk.promo.activity;

import com.epfly.base.ex.PromoException;
import com.epfly.base.ex.PromoMessageEnum;
import com.epfly.base.vo.BaseResp;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternUtils;
import org.springframework.core.type.ClassMetadata;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.http.ResponseEntity;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;

import java.beans.Introspector;
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Objects;

@Slf4j
@Configuration
public class ActivityFeignBeanFactoryPostProcessor implements BeanFactoryPostProcessor, ResourceLoaderAware {
    private ResourceLoader resourceLoader;

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
            ResourcePatternResolver resolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
            MetadataReaderFactory metaReader = new CachingMetadataReaderFactory(resourceLoader);
        try {
            Resource[] resources = resolver.getResources("classpath*:com/epfly/iface/promo/**/*.class");

            for (Resource r : resources) {
                MetadataReader reader = metaReader.getMetadataReader(r);
                ClassMetadata classMetadata = reader.getClassMetadata();
                if (!classMetadata.isInterface()) {
                    continue;
                }
                String className = classMetadata.getClassName();
                Class<?> iClass = ClassUtils.resolveClassName(className, ClassUtils.getDefaultClassLoader());
                String beanName = Introspector.decapitalize(iClass.getSimpleName()) + "Impl";
                if (beanFactory.containsBean(beanName)) {
                    continue;
                }

                Object o = Proxy.newProxyInstance(ClassUtils.getDefaultClassLoader(), new Class[]{iClass}, new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        String name = method.getName();
                        Class<?>[] parameterTypes = method.getParameterTypes();
                        Object activityServiceFeign = beanFactory.getBean(ActivityServiceFeign.class.getName());
                        Method fMethod = ReflectionUtils.findMethod(activityServiceFeign.getClass(), name, parameterTypes);
                        if (Objects.isNull(fMethod)) {
                            // ERR_100019("接口未开放远程调用")
                            throw new PromoException(PromoMessageEnum.ERR_430019);
                        }
                        ResponseEntity<BaseResp> responseEntity = (ResponseEntity<BaseResp>)fMethod.invoke(activityServiceFeign, args);
                        BaseResp resp = responseEntity.getBody();
                        if (!resp.success()) {
                            throw new PromoException(resp.getErrCode(), resp.getErrMsg());
                        }
                        return resp;
                    }
                });
                beanFactory.registerSingleton(beanName, o);

            }

        } catch (IOException e) {
            log.error("create outer bean exception ", e);
        }
    }

    @Override
    public void setResourceLoader(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }
}
